
oo::class create FilesNotebook {
    superclass Monitor
    variable ContainerID NotebookFrame Notebook Plugins FileTypes PopupDialog PopupAlertDialog

    constructor {pane plugins} {
        set ContainerID 0
        # set Pane [ttk::panedwindow $parent.pane -orient horizontal]
        set frame $pane.ln
        set sm [lindex [info class instances ::SettingMenu] 0]
        CloseFrame new $frame [subst {
            set ::IfShowWorkspace 0
            $sm ifShowWorkspace
        }]
        set NotebookFrame $frame
        # set frame [ttk::labelframe $Pane.ln -text Workspace]
        # $pane add $frame
        set Notebook [ttk::notebook $frame.notebook]
        pack $pane -fill both -expand 1 -padx 2 -pady {2 0}
        # pack $LabelFrame -fill both -expand 1 -padx 1
        pack $Notebook -fill both -expand 1
        tkdnd::drop_target register $Notebook *
        bind $Notebook <<Drop>> [subst {
            foreach f %D {
                if {\[file isfile \$f\]} {
                    [self] openFile \[[self] nextTabid \[$Notebook index current\]\] \$f
                }
            }
        }]

        # puts "$parent -> $Notebook"
        # set Plugins $plugins

        set Plugins [my insertSelfTONotifer $plugins]

        set FileTypes {
            {{Tcl Files} .tcl}
            {{All Files} *}
        }
        set PopupDialog [PopupDialog new .alert]
        set PopupAlertDialog [PopupAlertDialog new .conflict]

        bind $Notebook <<NotebookTabChanged>> [list [self] onNotebookTabChanged]
    }

    method getCurrentPad {} {
        set cont [my getContainObj [$Notebook index current]]
        if {$cont == {}} {return}
        return [set [info object namespace $cont]::Container].pad
    }

    method onNotebookTabChanged {} {
        set Notebook $Notebook
        set nbObj [self object]
        if {[$Notebook tabs] == {}} { return }
        set container [$nbObj getContainObj [$Notebook index current]]
        .status.readonly configure -variable [info object namespace $container]::ReadOnly
        set codepad [set [info object namespace $container]::CodePad]
        set coll [set [info object namespace $codepad]::ActionCollection]
        set factory [set [info object namespace $coll]::PluginFactory]
        set objs [set [info object namespace $factory]::Objs]
        foreach o $objs {
            if [info object class $o Notifier] {
                $o updateMonitor
                break
            }
        }
        cd [set [info object namespace $container]::Cwd]
    }

    method insertSelfTONotifer {plugins} {
        set ret {}
        foreach p $plugins {
            set type [lindex $p 0]
            if {$type == "notifier"} {
                set monitors [concat [self object] [lindex $p 1]]
                lappend ret [list $type $monitors]
            } else {
                lappend ret $p
            }
        }
        return $ret
    }

    method nextContainerID {} {
        incr ContainerID
        return $ContainerID
    }

    method isFileAlreadyOpened? {file} {
        foreach o [info class instances ::FileContainer] {
            if {[file split [set ${o}::File]] == [file split $file]} {
                return [set ${o}::Container]
            }
        }
    }

    method createNewContainer {tabid {file {}}} {
        if {[set container [my isFileAlreadyOpened? $file]] != {}} {
            $Notebook select $container
            return
        }

        set container [FileContainer new $Notebook.container[my nextContainerID] $Plugins $file]
        set containerFrame [set [info object namespace $container]::Container]
        $Notebook insert $tabid $containerFrame
        $Notebook tab $containerFrame -text \
            [expr {$file == {} ? " * " : [file tail $file]}]
        $Notebook select $containerFrame
        my AddPadWidgetToComplete $containerFrame.pad
        return $container
    }

    method AddPadWidgetToComplete {padWidget} {
        foreach c [info class instances Complete] {
            $c appendSearchWidget $padWidget
        }
    }

    method RemovePadWidgetFromComplete {padWidget} {
        foreach c [info class instances Complete] {
            $c removeSearchWidget $padWidget
        }
    }

    method getContainObj {tabid} {
        set frame [lindex [$Notebook tabs] $tabid]
        foreach f [info class instances ::FileContainer] {
            # puts "[set [info object namespace $f]::Container] --> $frame"
            if {[set [info object namespace $f]::Container] == $frame} { return $f }
        }
    }

    method nextTabid {tabid} {
        set endid [$Notebook index end]
        if {$tabid < $endid-1} {
            return [expr $tabid+1]
        } elseif {$tabid == $endid-1} {
            return end
        }
    }

    method closeContainer {tabid} {
        if {[set obj [my getContainObj $tabid]] != {}} {
            set padWidget [set [set [info object namespace $obj]::CodePad]::PadWidget]
            if [$padWidget edit modified] {
                switch [$PopupDialog popup "Save modified code?"] {
                    1 {
                        if [my saveFile $tabid] {
                            $Notebook forget $tabid
                            $obj destroy
                        }
                    }
                    0 {
                        $Notebook forget $tabid
                        $obj destroy
                    }
                }
            } else {
                $Notebook forget $tabid
                $obj destroy
            }
            my RemovePadWidgetFromComplete _$padWidget
        }
    }

    method openFileAt {currentTabid} {
        if {$currentTabid == "end"} {
            set cwd [pwd]
        } else {
            set cwd [set [info object namespace [my getContainObj $currentTabid]]::Cwd]
        }
        if {[set file [tk_getOpenFile -initialdir $cwd \
                           -filetype $FileTypes -title {Open File}]] != {}} {
            my openFile [my nextTabid $currentTabid] $file
        }
    }

    method openFile {tabid file} {
        if {[set container [my createNewContainer $tabid $file]] != {}} {
            my importFile $container $file
        }
    }

    method saveFile {tabid} {
        set obj [my getContainObj $tabid]
        set codePad [set [info object namespace $obj]::CodePad]
        set padWidget [set [info object namespace $codePad]::PadWidget]
        if ![$padWidget edit modified] { return }

        if {$obj == {}} {return}

        # delete complete part
        my DeleteCompletePart $padWidget

        set file [set [info object namespace $obj]::File]
        if {$file == {}} {
            return [my saveAsFile $tabid]
        } else {
            my exportFile $codePad $file
            return 1
        }
    }

    method saveAsFile {tabid} {
        set fileContainer [my getContainObj $tabid]

        # delete complete part
        set codePad [set [info object namespace $fileContainer]::CodePad]
        set padWidget [set [info object namespace $codePad]::PadWidget]
        my DeleteCompletePart $padWidget

        # puts "$tabid -> $fileContainer"
        if {[set file [tk_getSaveFile \
                           -initialdir [set [info object namespace $fileContainer]::Cwd] \
                           -filetype {{{All Files} *}} -title {Save File}]] != {}} {
                               if {[set container [my isFileAlreadyOpened? $file]] != {}} {
                                   $PopupAlertDialog popup "[file tail $file] already opened."
                                   return 0
                               }
                               $fileContainer setMetaData $file
                               $Notebook tab [set [info object namespace $fileContainer]::Container] \
                                 -text [file tail $file]
                               my exportFile [set [info object namespace $fileContainer]::CodePad] $file
                               return 1
                           }
        return 0
    }

    method DeleteCompletePart {padWidget} {
        foreach t [$padWidget tag names] {
            if {$t == "Complete"} {
                if {[$padWidget tag ranges Complete] != {}} {
                    $padWidget delete Complete.first Complete.last
                }
            }
        }
    }

    method exportFile {codePad file}  {
        set padWidget [set [info object namespace $codePad]::PadWidget]
        set fh [open $file w]
        puts -nonewline $fh [$padWidget get 1.0 {end -1l lineend}]
        close $fh
        my resetPadWidget [set [info object namespace $codePad]::PadWidget]
    }

    method importFile {fileContainer file} {
        set codepad [set [info object namespace $fileContainer]::CodePad]
        set padWidget [set [info object namespace $codepad]::PadWidget]

        $padWidget delete 1.0 end

        set fh [open $file r]
        $padWidget insert 1.0 [read $fh]
        # reset edit
        after idle [list [self object] resetPadWidget $padWidget 1]
        close $fh
    }

    method resetPadWidget {padWidget {ifResetEdit 0}} {
        set i 0; set ids [$padWidget tag range Complete]
        while {$i < [llength $ids]-1} {
            $padWidget delete [lindex $ids $i] [lindex $ids $i+1]
            incr i 2
        }
        if $ifResetEdit { $padWidget edit reset }
        $padWidget edit modified 0

        # To update monitors
        $padWidget mark set insert insert
    }

    method update {textWidget langObj} {
        set textWidget [string trimleft $textWidget _]
        set container [join [lrange [split $textWidget .] 0 end-1] .]
        set title [$Notebook tab $container -text]
        if [$textWidget edit modified] {
            if {$title == { * } || [string index $title end] == "*"} { return }
            $Notebook tab $container -text "$title*"
        } else {
            $Notebook tab $container -text [string trimright $title *]
        }
    }

    destructor {
        while {[set tab [$Notebook select]] != {}} {
            set tabid [lsearch [$Notebook tabs] $tab]
            my closeContainer $tabid
        }
        destroy $Notebook
    }
}